export interface EnumElement {
  key: string
  value: any
  name: string
  color?: string
  data?: any[]
}

interface EnumKeyObj {
  [key: string]: EnumElement
}

interface EnumValueObj {
  [value: string]: EnumElement
}

class SuperEnum {
  data: EnumElement[]

  private keyObj: EnumKeyObj

  private valueObj: EnumValueObj

  constructor(param: EnumElement[]) {
    const keyObj: EnumKeyObj = {}
    const valueObj: EnumValueObj = {}

    if (!Array.isArray(param)) {
      throw new Error('param is not an array!')
    }

    param.forEach((element) => {
      if (!element.key || !element.name) {
        return
      }
      // 根据key生成不同属性值，以便A.B.name类型的调用
      this[element.key] = element
      if (element.key !== element.value) {
        this[element.value] = element
      }
      // 使用对象存储键值对，方便快速查找
      keyObj[element.key] = element
      valueObj[element.value] = element
    })

    // 保存源数组
    this.data = param
    this.keyObj = keyObj
    this.valueObj = valueObj

    // 防止被修改
    Object.freeze(this)
  }

  // 根据key得到对象
  keyOf(key: string): EnumElement | undefined {
    return this.keyObj[key]
  }

  // 根据key得到对象
  valueOf(key: string): EnumElement | undefined {
    return this.valueObj[key]
  }

  // 根据key获取name值
  getNameByKey(key: string): string {
    const prop = this.keyOf(key)
    if (!prop) {
      const error = new Error('No enum constant') as any
      error.code = 'ENUM_NOT_FOUND'
      throw error
    }
    return prop.name
  }

  // 根据value获取name值
  getNameByValue(value: string): string {
    const prop = this.valueOf(value)
    if (!prop) {
      const error = new Error('No enum constant') as any
      error.code = 'ENUM_NOT_FOUND'
      throw error
    }
    return prop.name
  }

  // 根据key获取value值
  getValueByKey(key: string): any {
    const prop = this.keyOf(key)
    if (!prop) {
      const error = new Error('No enum constant') as any
      error.code = 'ENUM_NOT_FOUND'
      throw error
    }
    return prop.value
  }

  // 根据key获取color值
  getColorByKey(key: string): string | undefined {
    const prop = this.keyOf(key)
    if (!prop) {
      const error = new Error('No enum constant') as any
      error.code = 'ENUM_NOT_FOUND'
      throw error
    }
    return prop.color
  }

  // 返回源数组
  getData(): EnumElement[] {
    return this.data
  }
}

export default SuperEnum
